透過存取器可以更靈活的制物件屬性,在不同語言中都擁有類似的模式;本文介紹在 TypeScript 與 Angular 實務上是如何使用存取器。
※編譯器輸出的 JS 需要 ES5 以上。
// 1.設定一個產品類別
export class Product {
public id: string;
public name: string;
private _price: number; // 此為私有屬性(通常會+底線)
}
// 2.建立新的實例
let book = new Product();
// 3.設定序號、名稱、價格
book.id = "1";
book.name = "A_Book";
book._price = 100; //! 報錯 不能從外部訪問
為了解決不能使用私有屬性的問題,使用了存取器。
export class Product {
public id: string;
public name: string;
private _price: number;
public get price() { // 模擬呼叫
return this._price
}
public set price(v: number) { // 模擬賦值
this._price = v
}
}
let book = new Product();
book.id = "1";
book.name = "A_Book";
book.price = 100; // 成功:D
// 調用的其實不是私有屬性,而是同名的 getter,
// 然後 getter 傳回私有屬性的值。
額外應用:於 Setter 賦值時增加邏輯判斷
export class Product {
public id: string;
public name: string;
private _price: number;
public get price() {
return this._price
}
public set price(v: number) {
if(v===0){
console.log("Error.價格不得為0");
} else {
this._price = v
}
}
}
let book = new Product();
book.id = "1";
book.name = "A_Book";
book.price = 0; //! Error.價格不得為0
在 Angular 中存取器經常用於屬性更改、父組件傳值給子組件的方法。
父組件:Parent、子組件:Product
<app-product [name]="book" [price]="100"></app-product>
export class ProductComponent {
public id: string;
private _name: string;
private _price: number;
// 1.價格存取器
@Input
public get price() {
return this._price
}
public set price(v: number) {
this._price = v
}
// 2.名稱存取器
@Input
public get name() {
return this._name
}
public set price(v: string) {
this._name = v
}
}
<!--book-->
<p>{{name}}</p>
每當父組件更改屬性時,子組件 setter 就會被觸發。
也可像上面介紹 TypeScript 存取器篇章中,在 Input setter 設置邏輯判斷,不過有一些限制:
不要在 setter 使用 side effects。
副作用(side effects):如修改其他屬性的值、觸發某些事件,可能導致程式行為出現變化。
不要在 setter 使用 subscription(訂閱器)
不要在 setter 使用 changeDetector.detectChanges(),請改使用 changeDetector.markForCheck()。
TypeScript | 從 TS 開始學習物件導向 - Class 用法
Using Getters and Setters in TypeScript and Angular
【Day 23】TypeScript - 類別存取器(Accessors)